/*
 * This file is part of the Sx Framework Library.
 * 
 * Copyright (C) 2013 University of Colorado Denver
 * <min.choi@ucdenver.edu> <shane.transue@ucdenver.edu>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy 
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
 * copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in 
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 */
#ifndef SX_SCANNER_H
#define SX_SCANNER_H

/*
 * The Scanner class specifically operates on basic String data.
 */
#include <sxString.h>

namespace Sx {
namespace Util {

/*
 * The Scanner class provides a simple interface for parsing basic Ascii text
 * data from a string based on a provided delimiter.
 */
class Scanner {
public:
	/*
	 * Creates a scanner without any String data.
	 */
	Scanner();

	/*
	 * Basic copy consrtuctor.
	 */
	Scanner(const Scanner& scanner);

	/*
	 * Creates a new Scanner that will parse the provided String. In the
	 * process of parsing the string, tokens will be defined by the provided
	 * character delimiter.
	 */
	Scanner(String& string, char delimiter);

	/*
	 * Creates a new Scanner that will parse the provided String. In the
	 * process of parsing the string, tokens will be defined by the provided
	 * character delimiter.
	 */
	Scanner(const String& string, char delimiter);

	/*
	 * Creates a new Scanner that will parse the provided String. In the
	 * process of parsing the string, tokens will be defined by by the provided
	 * string delimiter.
	 */
	Scanner(String& string, String delimiter = " ");

	/*
	 * Creates a new Scanner that will parse the provided String. In the
	 * process of parsing the string, tokens will be defined by by the provided
	 * string delimiter.
	 */
	Scanner(const String& string, String delimiter = " ");

	~Scanner();

	/*
	 * If this Scanner contains string data and valid tokens to be parsed,
	 * then this function will return true; otherwise this function will
	 * return false.
	 */
	bool hasNext() const;

	/*
	 * Based on the defined delimiter, the next token of this Scanners string
	 * data will be returned, if there is any valid token remaining.
	 */
	String next();

	/*
	 * Returns the next line of this Scanners string data.
	 */
	String nextLine();

	/*
	 * Returns the next token in this Scanners string data. The state of the
	 * scanner is not modified in this function.
	 */
	String peek();

	/*
	 * Removes the next token from this Scanners string data.
	 */
	String pop();

	/*
	 * Returns the next character contained in this Scanners string data at
	 * the current position. This function does not modify the state of the
	 * string data in this Scanner.
	 */
	char peekChar();

	/*
	 * Returns the next character in this Scanners string data.
	 */
	char nextChar();

	/*
	 * This function identifies the next token and then parses the token into
	 * a long value. The parsed long value is returned.
	 */
	long nextLong();

	/* 
	 * This function identifies the next token and then parses the token into
	 * an int value. The parsed int value is returned.
	 */
	int nextInt();

	/*
	 * This function identifies the next token and then parses the token into
	 * a double value. The parsed double value is returned.
	 */
	double nextDouble();

	/*
	 * This function identifies the next token and then parses the token into
	 * a float value. The parsed float value is returned.
	 */
	float nextFloat();

	unsigned int getLength() const;
	String getString() const;

	/*
	 * Returns the delimiter used to tokenize this Scanners string data.
	 */
	String getDelimiter() const;

	/*
	 * Pushes the last popped token back onto this Scanners string data.
	 * The number of steps represents the number of tokens that should be
	 * pushed back.
	 */
	void push(unsigned int steps = 1);

	/*
	 * Advances the Scanner by one token. This is equivalent to the next
	 * function however it assumes that the token data is not important and
	 * multiple tokens can be skipped using this function.
	 */
	void increment(unsigned int steps = 1);

	/*
	 * Restores previous token reads from this Scanner. If the provided number
	 * of steps exceeds the previous number of reads this Scanner will begin
	 * parsing from the beginning of the current string data.
	 */
	void decrement(unsigned int steps = 1);

	/*
	 * Provides this Scanner with new string data and delimiter. Positional
	 * information is lost and the scanner is reset.
	 */
	void scan(String data, String delimiter);

	/*
	 * Resets the state of this Scanner. next() operations performed after a
	 * reset will be performed at the beginning of this Scanners string data.
	 */
	void reset();

	/*
	 * Undoes the provided number of next() operations. This pushes the last
	 * steps number of tokens back onto this Scanners string data.
	 */
	void undo(unsigned int steps);

	/*
	 * Sets the string data of this Scanner to be scanned.
	 */
	void setString(String string);

	/*
	 * Sets the delimiter used to tokenize this Scanners string data.
	 */
	void setDelimiter(String delimiter);

	void operator ++ ();
	void operator -- ();

private:
	/*
	 * The undo buffer provides a history of tokens parsed from the internal
	 * string of this Scanner. This allows for look-ahead operations.
	 */
	ArrayList<unsigned int> undoBuffer;
	
	/*
	 * The actual string data that is parsed.
	 */
	String data;

	/*
	 * Delimiter that determines how tokens are formed.
	 */
	String delimiter;

	/*
	 * Maintains the current position in this Scanners string data. This
	 * determines the position from which the next token will be parsed.
	 */
	int substringLength;

	/*
	 * While parsing this Scanners string data, there may be instances where
	 * there are several consecutive delimiters. This function identifies the
	 * delimiters and skips over them to provide the next valid token as a
	 * utility function.
	 */
	void skipDelimiters();
	unsigned int getLinePos(String string);
};

}

}

#endif
